using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Windows.Forms;
using System.Collections;
using System.Collections.Specialized;
using System.Drawing;
using System.Runtime.InteropServices;

namespace TotalCrytography
{
    // reference from codeproject
    sealed class FileIcons
    {
        private static Hashtable iconIndex = new Hashtable();

        private static ImageList smallImageList = new ImageList();

        private static ImageList largeImageList = new ImageList();

        public ImageList SmallImageList
        {
            get { return smallImageList; }
        }

        public ImageList LargeImageList
        {
            get { return largeImageList; }
        }

        private FileIcons() { }

        public static readonly FileIcons Instance = new FileIcons();

        public int GetIconIndex(FileSystemInfo pFile)
        {
            int idx;
            if (iconIndex.Contains(pFile.FullName))
                idx = (int)iconIndex[pFile.FullName];
            else
            {
                smallImageList.Images.Add(IconReader.Instance.GetSmallTypeIcon(pFile));
                largeImageList.Images.Add(IconReader.Instance.GetLargeTypeIcon(pFile));
                idx = smallImageList.Images.Count;
                iconIndex.Add(pFile.FullName, idx);
                
            }
            return idx;
        }
    }
    sealed class IconReader
    {
        public static readonly IconReader Instance = new IconReader();

        public Icon GetSmallTypeIcon(FileSystemInfo pFile)
        {            
            
            SHFILEINFO psfi = new SHFILEINFO();
            uint uFlags = SHGFI_ICON | SHGFI_SMALLICON | SHGFI_USEFILEATTRIBUTES;
            if(pFile is DirectoryInfo)            
                SHGetFileInfo(pFile.FullName, FILE_ATTRIBUTE_DIRECTORY, ref psfi, (uint)Marshal.SizeOf(psfi), uFlags);
            else
            {
                uint fileAttribute = FILE_ATTRIBUTE_ARCHIVE
                                    | FILE_ATTRIBUTE_COMPRESSED
                                    | FILE_ATTRIBUTE_HIDDEN
                                    | FILE_ATTRIBUTE_NORMAL
                                    | FILE_ATTRIBUTE_READONLY
                                    | FILE_ATTRIBUTE_SYSTEM;

                SHGetFileInfo(pFile.FullName, fileAttribute, ref psfi,
                    (uint)Marshal.SizeOf(psfi), uFlags);
            }            
            Icon icon = (Icon)Icon.FromHandle(psfi.hIcon).Clone();
            
            DestroyIcon(psfi.hIcon);
            return icon;            
        }

        public Icon GetLargeTypeIcon(FileSystemInfo pFile)
        {
            SHFILEINFO psfi = new SHFILEINFO();
            uint uFlags = SHGFI_ICON | SHGFI_LARGEICON | SHGFI_USEFILEATTRIBUTES;
            if (pFile is DirectoryInfo)            
                SHGetFileInfo(pFile.FullName, FILE_ATTRIBUTE_DIRECTORY, ref psfi, (uint)Marshal.SizeOf(psfi), uFlags);
            else
            {
                uint fileAttribute = FILE_ATTRIBUTE_ARCHIVE
                                     | FILE_ATTRIBUTE_COMPRESSED
                                     | FILE_ATTRIBUTE_HIDDEN
                                     | FILE_ATTRIBUTE_NORMAL
                                     | FILE_ATTRIBUTE_READONLY
                                     | FILE_ATTRIBUTE_SYSTEM;
                SHGetFileInfo(pFile.FullName, fileAttribute, ref psfi,
                    (uint)Marshal.SizeOf(psfi), uFlags);
            }

            Icon icon = (Icon)Icon.FromHandle(psfi.hIcon).Clone();
            DestroyIcon(psfi.hIcon);
            return icon;
        }

        const int MAX_PATH = 256;
        const int NAMESIZE = 80;
        const uint SHGFI_ICON = 0x100;				
        const uint SHGFI_SMALLICON = 0x1;			
        const uint SHGFI_LARGEICON = 0x0;			
        const uint SHGFI_USEFILEATTRIBUTES = 0x10;	
        const uint FILE_ATTRIBUTE_ARCHIVE = 0x20;
        const uint FILE_ATTRIBUTE_COMPRESSED = 0x800;
        const uint FILE_ATTRIBUTE_DIRECTORY = 0x10;
        const uint FILE_ATTRIBUTE_HIDDEN = 0x2;
        const uint FILE_ATTRIBUTE_NORMAL = 0x0;
        const uint FILE_ATTRIBUTE_READONLY = 0x1;
        const uint FILE_ATTRIBUTE_SYSTEM = 0x4;

      
        [StructLayout(LayoutKind.Sequential)]
        private struct SHFILEINFO
        {
            public IntPtr hIcon;
            public int iIcon;
            public uint dwAttributes;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)]
            public string szDisplayName;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = NAMESIZE)]
            public string szTypeName;
        };

        [DllImport("Shell32.dll")]
        private static extern IntPtr SHGetFileInfo(string pszPath,
            uint dwFileAttributes,
            ref SHFILEINFO psfi,
            uint cbFileInfo,
            uint uFlags);
        [DllImport("User32.dll")]
        public static extern int DestroyIcon(IntPtr hIcon);
  

        private IconReader() { }
    }
}
